/**
 * 
 */
package ar.com.fiuba.team2.services;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

import org.apache.axis.utils.StringUtils;
import org.apache.axis2.AxisFault;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import ar.com.fiuba.team2.model.Chat;
import ar.com.fiuba.team2.model.MensajeChat;
import ar.com.fiuba.team2.model.MiembroChat;
import ar.com.fiuba.team2.model.Miembros;
import ar.com.fiuba.team2.model.Result;
import ar.com.fiuba.team2.parser.ChatParser;
import ar.com.fiuba.team2.parser.MensajeParser;
import ar.com.fiuba.team2.parser.MiembroParser;
import ar.com.fiuba.team2.services.fake.IntegracionFakeStub;

import com.ws.services.IntegracionStub;
import com.ws.services.IntegracionStub.GuardarDatos;
import com.ws.services.IntegracionStub.GuardarDatosResponse;
import com.ws.services.IntegracionStub.SeleccionarDatos;
import com.ws.services.IntegracionStub.SeleccionarDatosResponse;

/**
 * Singleton with logic to get and set data to integration services.
 * 
 * @author sergio
 */
public class IntegrationHandler {

	private static final String RESULT_OK = "2";
	public static String URL = "http://localhost:8080/axis2/services/integracion";
	public static boolean test = false;
	
	private static IntegrationHandler instance;
	private IntegracionStub integracionStub;
	
	private Logger log = LogManager.getLogger(this.getClass());
	
	/**
	 * constructor.
	 * 
	 * @throws AxisFault
	 */
	private IntegrationHandler() throws AxisFault {
		if (test) {
			integracionStub = new IntegracionFakeStub(URL);
		} else {
			integracionStub = new IntegracionStub(URL);
		}
	}

	/**
	 * Devuelve instancia de handler.
	 * 
	 * @return handler
	 * @throws AxisFault
	 */
	public synchronized static IntegrationHandler getInstance()
			throws AxisFault {
		if (instance == null) {
			instance = new IntegrationHandler();
		}

		return instance;
	}

	/**
	 * Guarga o actualiza el Chat recibido.
	 * De guardarlo, el chatId es actualizado antes de terminar.
	 * 
	 * @param chat a actualizar.
	 * @return boolean con el resultado de la operación
	 * @throws RemoteException
	 */
	public boolean setChat(Chat chat) throws RemoteException {
		GuardarDatos datos = new GuardarDatos();
		
		StringBuilder str = new StringBuilder("<WS>");
		str.append(chat.toXML());
		str.append("</WS>");
		
		datos.setXml(str.toString());

		log.info("Enviando mensaje " + str.toString());
		GuardarDatosResponse guardado = integracionStub.guardarDatos(datos);
		log.info("Respuesta recibida " + guardado.get_return());
		
		long resultado = ChatParser.parseResultado(guardado.get_return(), chat.getMeessage());
		
		chat.getData().setIdChat(resultado);
		return RESULT_OK.equals(chat.getMeessage().getCode());
	}

	/**
	 * Obtiene el chat correspondiente al id.
	 * 
	 * @param chatId a buscar.
	 * @return Chat con los datos cargados, null si no lo encuentra.
	 */
	public Chat getChat(long chatId) {

		SeleccionarDatos seleccionarDatos = new SeleccionarDatos();

		StringBuilder str = new StringBuilder("<WS><Chat><id>");
		str.append(chatId).append("</id></Chat></WS>");

		log.info("Enviando mensaje " + str.toString());
		seleccionarDatos.setXml(str.toString());

		SeleccionarDatosResponse guardado;
		Chat chat = null;
		try {
			guardado = integracionStub.seleccionarDatos(seleccionarDatos);
			log.info("Respuesta recibida " + guardado.get_return());
			chat = ChatParser.parseChat(guardado.get_return());
		} catch (RemoteException e) {
			log.error("Consultando por chat " + chatId, e);
		} catch (RuntimeException e) {
			log.error("Consultando por chat " + chatId, e);
		}

		return chat;

	}

	/**
	 * Actualiza el Miembro antes de guardar la relación, usando saveMiembro().
	 * Luego guarda la relación creada.
	 * 
	 * TODO Falta testear
	 * 
	 * @param miembro
	 * @param chat
	 * @throws RemoteException
	 */
	public void addMiembro(MiembroChat miembro, Chat chat)
			throws RemoteException {
		
		if (this.saveMiembro(miembro)) {
			chat.getData().addMiembro(miembro);
			if (this.setChat(chat)){
				log.info("La relación entre miembro "
						+ miembro.getId() + " y el chat " 
						+ chat.getData().getIdChat() 
						+ " se guardó con exito.");				
			} else {
				log.warn("La relación entre miembro "
						+ miembro.getId() + " y el chat " 
						+ chat.getData().getIdChat() 
						+ " no se pudo realizar por "
						+ chat.getMeessage().getDescription());	
			}
		} else {
			log.warn("no fue posible guardar relación " + miembro + " en " + chat);
		}
	}

	/**
	 * 
	 * TODO Falta testear
	 * 
	 * @param chatId
	 * @return
	 * @throws RemoteException
	 */
	public Miembros getAllOnlineMembers(long chatId) throws RemoteException {
		StringBuilder str = new StringBuilder(
		"<WS><miembros_chat_chats><chat_id>");
		str.append(chatId);
		str.append("</chat_id></miembros_chat_chats></WS>");
		

		SeleccionarDatos seleccionarDatos = new SeleccionarDatos();
		seleccionarDatos.setXml(str.toString());

		SeleccionarDatosResponse response = integracionStub
				.seleccionarDatos(seleccionarDatos);
		
		List<MiembroChat> allMembers = MiembroParser.parseMiembros(response.get_return());
		
		List<MiembroChat> members = new ArrayList<MiembroChat>();
		
		Miembros miembros = new Miembros();
		
		for (MiembroChat m : allMembers) {
			members.add(m);
		}
		
		miembros.setMessages(allMembers.toArray(new MiembroChat[members.size()]));
		
		return miembros;
	}

	/**
	 * TODO Falta testear
	 * 
	 * @param chatId
	 * @return
	 * @throws RemoteException
	 */
	public MensajeChat[] getAllMensaje(long chatId) throws RemoteException {
		StringBuilder str = new StringBuilder(
		"<WS><MensajeChat><chatId>");
		str.append(chatId);
		str.append("</chatId></MensajeChat></WS>");

		SeleccionarDatos seleccionarDatos = new SeleccionarDatos();
		seleccionarDatos.setXml(str.toString());

		SeleccionarDatosResponse response = integracionStub.seleccionarDatos(seleccionarDatos);
		
		List<MensajeChat> allMensajes = MensajeParser.parseAllMensajes(response.get_return());
		
		return allMensajes.toArray(new MensajeChat[allMensajes.size()]);
	}
	
	/**
	 * Busca por nombre, por id, o por ambos.
	 * En el caso de haber más de una coincidencia, devuelve el último.
	 * 
	 * @param miembro {@link MiembroChat} a buscar
	 * @return boolean con el resultado de la busqueda.
	 * @throws RemoteException
	 */
	public boolean getMiembro(MiembroChat miembro) throws RemoteException {
		StringBuilder str = new StringBuilder("<WS><MiembroChat>");
		if (miembro.getId() != 0) {
			str.append("<id>").append(miembro.getId()).append("</id>");
		}
		if (!StringUtils.isEmpty(miembro.getNombre())) {
			str.append("<nombre>").append(miembro.getNombre()).append("</nombre>");			
		}
		str.append("</MiembroChat></WS>");

		SeleccionarDatos seleccionarDatos = new SeleccionarDatos();
		log.info("Enviando mensaje para buscar miembro " + str.toString());
		seleccionarDatos.setXml(str.toString());

		SeleccionarDatosResponse response = integracionStub
				.seleccionarDatos(seleccionarDatos);
		log.info("Resultado de buscar miembro " + str.toString());

		return MiembroParser.parseMiembro(response.get_return(), miembro);
	}

	/**
	 * Crea un nuevo miembro si miembro.getId() == 0, o lo actualiza si no.
	 * De crearlo, se actualiza el valor del id antes de terminar.
	 * 
	 * @param miembro {@link MiembroChat} a guardar
	 * @return true si se guardó con éxito
	 * @throws RemoteException
	 */
	public boolean saveMiembro(MiembroChat miembro) throws RemoteException {
		StringBuilder str = new StringBuilder("<WS>");
		str.append(miembro.toXML());
		str.append("</WS>");
		
		GuardarDatos datos = new GuardarDatos();
		datos.setXml(str.toString());
		log.info("Enviando mensaje " + str.toString());
		
		GuardarDatosResponse guardado = integracionStub.guardarDatos(datos);

		log.info("Respuesta recibida " + guardado.get_return());
		
		long resultado = MiembroParser.parseResultado(guardado.get_return(), null);
		miembro.setId(resultado);
		
		return resultado > 0;
	}

	/**
	 * TODO Falta testear
	 * 
	 * @param mChat
	 * @param scopeId
	 * @return
	 * @throws RemoteException
	 */
	public boolean esMiembro(MiembroChat mChat, long scopeId)
			throws RemoteException {

		boolean result = false;
		Chat chat = getChat(scopeId);
		if (chat != null) {
			result = chat.getData().getMiembros().contains(mChat);
		}
		return result;
	}

	/**
	 * Guarda el mensaje asociado al chat.
	 * 
	 * @param mensaje
	 * @param chat
	 * @throws RemoteException 
	 */
	public void saveMensaje(MensajeChat mensaje, Chat chat) throws RemoteException {
		StringBuilder str = new StringBuilder("<WS><MensajeChat>");
		str.append("<idChat>").append(chat.getData().getIdChat()).append("</idChat>");
		str.append("<contenido>").append(mensaje.getContenidoMensaje()).append("</contenido>");
		str.append("<miembroChatId>22</miembroChatId>");
		str.append("</MensajeChat></WS>");

		GuardarDatos datos = new GuardarDatos();
		datos.setXml(str.toString());
		log.info("Enviando mensaje " + str.toString());
		
		GuardarDatosResponse guardado = integracionStub.guardarDatos(datos);

		log.info("Respuesta recibida " + guardado.get_return());
		
		Result result = new Result();
		long parseResultado = MensajeParser.parseResultado(guardado.get_return(), result );
		
		mensaje.setId(parseResultado);
	}

	/**
	 * Guarda el mensaje asociado al chat.
	 * 
	 * @param mensaje
	 * @param chat
	 * @throws RemoteException 
	 */
	public void getMensaje() throws RemoteException {
		StringBuilder str = new StringBuilder("<WS><MensajeChat>");
		str.append("<id>11</id>");
		str.append("</MensajeChat></WS>");

		SeleccionarDatos datos = new SeleccionarDatos();
		datos.setXml(str.toString());
		log.info("Enviando mensaje " + str.toString());
		
		SeleccionarDatosResponse guardado = integracionStub.seleccionarDatos(datos);

		log.info("Respuesta recibida " + guardado.get_return());
		
	}
}
